home *** CD-ROM | disk | FTP | other *** search
/ Aminet 33 / Aminet 33 - October 1999.iso / Aminet / util / misc / VMM_src.lha / VMM / pagehandler.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-18  |  14.9 KB  |  620 lines

  1. #include <exec/types.h>
  2. #include "defs.h"
  3.  
  4. static char rcsid [] = "$Id: pagehandler.c,v 3.9 95/12/16 18:36:40 Martin_Apel Exp $";
  5.  
  6. /***********************************************************************/
  7.  
  8. PRIVATE ULONG OrigRootTableContents [NUM_PTR_TABLES];
  9. extern ULONG RootTableContents [NUM_PTR_TABLES];
  10. PRIVATE void *ResetHandlerData;
  11. PRIVATE UWORD ResetSignal;
  12. PRIVATE BOOL RootTableModified;
  13.  
  14. #define MIN(a,b) ((a)<(b)?(a):(b))
  15.  
  16.  
  17. PRIVATE int InitPagetables (void)
  18.  
  19. /* Physical addresses have to be used. Later the physical address of
  20.  * the allocated chunk is used. For now (68040.library does an identical
  21.  * mapping) we use logical addresses.
  22.  */
  23.  
  24. {
  25. ULONG *FirstPage;
  26. int i;
  27. int rc;
  28.  
  29. NewList (&FrameList);
  30. NewList (&FrameAllocList);
  31.  
  32. for (i = 0; i < NUM_PTR_TABLES; i++)
  33.   {
  34.   RootTableContents [i] =
  35.   OrigRootTableContents [i] = *(RootTable + ROOTINDEX (VirtAddrStart) + i);
  36.   *(RootTable + ROOTINDEX (VirtAddrStart) + i) = BUILD_DESCR (LOCUNUSED,
  37.                                                  PAGED_OUT, PT_TABLE);
  38.   }
  39.  
  40. RootTableModified = TRUE;
  41.  
  42. if ((FirstPage = AllocAligned (PAGESIZE, MEMF_PUBLIC | MEMF_REVERSE,
  43.                                PAGEALIGN, 0L)) == NULL)
  44.   {
  45.   PRINT_DEB ("Couldn't allocate first frame", 0L);
  46.   return (ERR_NOT_ENOUGH_MEM);
  47.   }
  48.  
  49. if ((rc = MarkAddress (VirtAddrStart, PAGESIZE, CACHE_MODE | PAGE_RESIDENT,
  50.                        (ULONG)FirstPage, FALSE)) != SUCCESS)
  51.   {
  52.   FreeMem (FirstPage, PAGESIZE);
  53.   return (rc);
  54.   }
  55.  
  56. if ((rc = MarkAddress (VirtAddrStart + PAGESIZE,
  57.                   (ULONG)MIN (VirtAddrEnd - (VirtAddrStart + PAGESIZE), PartSize),
  58.                   BUILD_DESCR (LOCUNUSED, PAGED_OUT, 0), 0L, FALSE)) != SUCCESS)
  59.   return (rc);
  60.  
  61. PRINT_DEB ("Pointer and page table initialized", 0L);
  62.  
  63. /* Allocate misc page frames */
  64.  
  65. for (i = 0; i < CurrentConfig.MinMem / PAGESIZE; i++)
  66.   {
  67.   if (!AddFrame (0L))
  68.     {
  69.     PRINT_DEB ("Couldn't allocate %ld bytes", CurrentConfig.MinMem);
  70.     return (ERR_NOT_ENOUGH_MEM);
  71.     }
  72.   }
  73.  
  74. PRINT_DEB ("Frames allocated", 0L);
  75.  
  76. CacheClearU ();
  77. (*PFlushA) ();
  78.  
  79. return (SUCCESS);
  80. }
  81.  
  82. /*********************************************************************/
  83.  
  84. PRIVATE void ResetHandler (void)
  85.  
  86. {
  87. PRINT_DEB ("Sending reset signal to pagehandler", 0L);
  88. Signal (PageHandlerTask, 1L << ResetSignal);
  89.  
  90. if (IsA3000)
  91.   {
  92.   UBYTE *ForceReset = (UBYTE*)0xde0002;
  93.  
  94.   *ForceReset &= ~0x80;
  95.   }
  96.  
  97. /* The following seems to cause a GURU 80000038 upon reset on A3000's and 
  98.  * sometimes a GURU 8000000b on A4000's. 
  99.  * On a A3000 without this the machine hung upon reset. Now enabled only for A3000
  100.  */
  101.  
  102. if (IsA3000)
  103.   RestoreMMUState30 ();
  104. }
  105.  
  106. /*********************************************************************/
  107.  
  108. PRIVATE int InitPageHandler (void)
  109.  
  110. {
  111. ULONG *VectorTable;
  112. int rc;
  113.  
  114. /* 16 signals per task are guaranteed, so the following three lines
  115.  * can't fail
  116.  */
  117.  
  118. PageFaultSignal       = AllocSignal (-1L);
  119. PageHandlerQuitSignal = AllocSignal (-1L);
  120. ResetSignal           = AllocSignal (-1L);
  121.  
  122. ResetInProgress = FALSE;
  123.  
  124. if ((PageHandlerPort = CreateMsgPort ()) == NULL)
  125.   return (ERR_NOT_ENOUGH_MEM);
  126.  
  127. NumTables = 0;
  128.  
  129. if ((rc = OpenPageFile ()) != SUCCESS)
  130.   {
  131.   PRINT_DEB ("InitPageHandler: Couldn't open paging file", 0L);
  132.   return (rc);
  133.   }
  134.  
  135. PRINT_DEB ("Paging file opened", 0L);
  136.  
  137. PartSize = ALIGN_DOWN (PartSize, PAGESIZE);
  138.  
  139. if ((rc = InitPagetables ()) != SUCCESS)
  140.   return (rc);
  141.  
  142. PRINT_DEB ("Page tables initialized", 0L);
  143.  
  144. if ((rc = InitCache ()) != SUCCESS)
  145.   {
  146.   PRINT_DEB ("Couldn't init cache", 0L);
  147.   return (rc);
  148.   }
  149.  
  150. if ((ResetHandlerData = InstallResetHandler (ResetHandler, -32L)) == NULL)
  151.   PRINT_DEB ("Couldn't install reset handler", 0L);
  152.  
  153. Forbid ();
  154. VectorTable = (ULONG*)ReadVBR ();
  155. OrigTrapHandler = (void (*) ()) *(VectorTable + 2);
  156.  
  157. PRINT_DEB("VBR=%08lx",(ULONG)VectorTable);
  158.  
  159. switch (ProcessorType)
  160.   {
  161.   case PROC_68060: *(VectorTable + 2) = (ULONG)&TrapHandler60;
  162.                    break;
  163.   case PROC_68040: *(VectorTable + 2) = (ULONG)&TrapHandler40;
  164.                    break;
  165.   case PROC_68851:
  166.   case PROC_68030: *(VectorTable + 2) = (ULONG)&TrapHandler30;
  167.                    break;
  168. #ifdef DEBUG
  169.   default:
  170.     PRINT_DEB ("InitPageHandler: Unknown processor type", 0L);
  171.     ColdReboot ();
  172. #endif
  173.   }
  174.  
  175. CacheClearU ();
  176. Permit ();
  177. PRINT_DEB ("Trap-Vector set", 0L);
  178.  
  179. return (SUCCESS);
  180. }
  181.  
  182. /***********************************************************************/
  183.  
  184. PRIVATE void Cleanup_PageHandler (void)
  185.  
  186. {
  187. ULONG *VectorTable;
  188. int i;
  189.  
  190. if (OrigTrapHandler != NULL)
  191.   {
  192.   Forbid ();
  193.   VectorTable = (ULONG*)ReadVBR ();
  194.   *(VectorTable + 2) = (ULONG) OrigTrapHandler;
  195.   CacheClearU ();
  196.   Permit ();
  197.   }
  198.  
  199. PRINT_DEB ("Before killing pointer tables", 0L);
  200.  
  201. if (RootTableModified)
  202.   {
  203.   for (i = ROOTINDEX (VirtAddrStart);
  204.        i < ROOTINDEX (VirtAddrStart) + NUM_PTR_TABLES; i++)
  205.     {
  206.     if (TABLE_RESIDENT_P (*(RootTable + i)))
  207.       {
  208.       if (KillPointerTable ((ULONG*)ALIGN_DOWN (*(RootTable + i), POINTERTABALIGN),
  209.                             TRUE))
  210.         {
  211.         MarkPage (*(RootTable + i), CACHEABLE);
  212.         *(RootTable + i) = OrigRootTableContents [i - ROOTINDEX (VirtAddrStart)];
  213.         }
  214.       }
  215.     }
  216.  
  217.   CacheClearU ();
  218.   (*PFlushA) ();
  219.   }
  220.  
  221. PRINT_DEB ("Removing reset handler", 0L);
  222. RemoveResetHandler (ResetHandlerData);
  223.  
  224. PRINT_DEB ("Killing map", 0L);
  225.  
  226. KillCache ();
  227.  
  228. if (PartSize != 0)
  229.   ClosePageFile ();
  230.  
  231. PRINT_DEB ("Page file closed", 0L);
  232.  
  233. RemAllFrames ();
  234.  
  235. PRINT_DEB ("All frames freed", 0L);
  236.  
  237. if (PageHandlerPort != NULL)
  238.   DeleteMsgPort (PageHandlerPort);
  239.  
  240. FreeSignal ((ULONG)PageFaultSignal);
  241. FreeSignal ((ULONG)PageHandlerQuitSignal);
  242. FreeSignal ((ULONG)ResetSignal);
  243. }
  244.  
  245. /***********************************************************************/
  246.  
  247. PRIVATE BOOL LockResidentPage (ULONG Page)
  248.  
  249. /* Tries to lock a page in memory, if it is already resident.
  250.  * It can only lock it if there are still unlocked pages in memory.
  251.  * This has to be handled asynchroneously.
  252.  */
  253. {
  254. ULONG *root_entry,
  255.       *pointer_entry,
  256.       *page_entry;
  257.  
  258. PRINT_DEB ("Received lock msg for address %lx", Page);
  259.  
  260. root_entry = RootTable + ROOTINDEX (Page);
  261. pointer_entry = (ULONG*)ALIGN_DOWN (*root_entry, POINTERTABALIGN) +
  262.                 POINTERINDEX (Page);
  263. if (TABLE_INVALID_P (*pointer_entry))
  264.   {
  265.   PRINT_DEB ("Couldn't lock page", 0L);
  266.   return (FALSE);  
  267.   }
  268.  
  269. page_entry = (ULONG*)ALIGN_DOWN (*pointer_entry, PAGETABALIGN) +
  270.              PAGEINDEX (Page);
  271.  
  272. Forbid ();
  273.  
  274. if (PAGE_RESIDENT_P (*page_entry))
  275.   {
  276.   if (!LOCKED_P (*page_entry))
  277.     {
  278.     if ((NumLocked + NumTables + 5 > NumPageFrames) && !AddFrame (0L))
  279.       {
  280.       Permit ();
  281.       PRINT_DEB ("Couldn't lock page. NumLocked = %ld", NumLocked);
  282.       return (FALSE);
  283.       }
  284.  
  285.     PRINT_DEB ("Locking resident page %lx", Page);
  286.     NumLocked++;
  287.     *page_entry |= LOCKED;
  288.     (*PFlushP) (Page);
  289.     }
  290.   Permit ();
  291.   return (TRUE);
  292.   }
  293.  
  294. Permit ();
  295. return (FALSE);
  296. }
  297.  
  298. /***********************************************************************/
  299.  
  300. PRIVATE void LockPage (ULONG Page)
  301.  
  302. {
  303. if (LockResidentPage (Page))
  304.   {
  305.   ThisPageLocked = TRUE;
  306.   Signal ((struct Task*)VM_ManagerProcess, 1L << LockAckSignal);
  307.   }
  308. else
  309.   {
  310.   struct TrapStruct *LockFault;
  311.  
  312.   Forbid ();
  313.   if ((LockFault = (struct TrapStruct*)RemHead (&Free)) == NULL)
  314.     {
  315.     Permit ();
  316.     ThisPageLocked = FALSE;
  317.     Signal ((struct Task*)VM_ManagerProcess, 1L << LockAckSignal);
  318.     return;
  319.     }
  320.  
  321.   Permit ();
  322.   LockFault->FaultTask = (struct Task*)LOCK_TASK;
  323.   LockFault->FaultAddress = Page;
  324.   AddPageReq (LockFault);
  325.   SetSignal (1L << PageFaultSignal, 1L << PageFaultSignal);
  326.   }
  327. }
  328.  
  329. /***********************************************************************/
  330.  
  331. PRIVATE void UnlockAllPages (void)
  332.  
  333. {
  334. struct FrameDescr *tmp_fd;
  335.  
  336. for (tmp_fd = (struct FrameDescr*)FrameList.lh_Head;
  337.      tmp_fd->FDNode.mln_Succ != NULL;
  338.      tmp_fd = (struct FrameDescr*) tmp_fd->FDNode.mln_Succ)
  339.   {
  340.   if ((tmp_fd->PageType == PT_PAGE) && LOCKED_P (*(tmp_fd->PageDescr)))
  341.     {
  342.     Forbid ();
  343.     *(tmp_fd->PageDescr) &= ~LOCKED;
  344.     (*PFlushP) (tmp_fd->LogAddr);
  345.     Permit ();
  346.     }
  347.   }
  348.  
  349. NumLocked = 0;
  350. }
  351.  
  352. /***********************************************************************/
  353.  
  354. PRIVATE void FreePages (ULONG Start, ULONG Size)
  355.  
  356. {
  357. ULONG start_page,
  358.       end_page,
  359.       tmp,
  360.       *desc;
  361.  
  362. struct FrameDescr *cur,
  363.                   *succ;
  364.  
  365. /*
  366. PRINT_DEB ("Received FreePageReq for address %lx", Start);
  367. PRINT_DEB ("                         size    %ld", Size);
  368. */
  369. start_page = ALIGN_UP(Start, PAGESIZE);
  370. end_page   = ALIGN_DOWN (Start + Size, PAGESIZE);
  371.  
  372. /* Two passes have to be made: First for all the non-resident pages.
  373.  * For them the corresponding swap page is freed.
  374.  * The second pass loops through all pages frames, marking those as
  375.  * unused which lie within the given address range.
  376.  */
  377.  
  378. /* First pass */
  379.  
  380. tmp = start_page;
  381. while (tmp < end_page)
  382.   {
  383.   desc = (ULONG*)ALIGN_DOWN (*(RootTable + ROOTINDEX (tmp)), POINTERTABALIGN);
  384.   desc = desc + POINTERINDEX (tmp);
  385.  
  386.   if (TABLE_INVALID_P (*desc))
  387.     {
  388.     tmp += PAGES_PER_TABLE * PAGESIZE;
  389.     continue;
  390.     }
  391.  
  392.   desc = (ULONG*)ALIGN_DOWN (*desc, PAGETABALIGN) + PAGEINDEX (tmp);
  393.   tmp += PAGESIZE;
  394.   if (PAGE_RESIDENT_P (*desc))
  395.     continue;          /* Not interested in resident pages in this pass */
  396.  
  397.   if (STATE_FROM_DESCR(*desc) == COMING_IN)
  398.     continue;
  399.  
  400.   Forbid ();
  401.   if (PGNUM_FROM_DESCR (*desc) != LOCUNUSED)
  402.     {
  403.     FreePageOnDisk (PGNUM_FROM_DESCR (*desc));
  404.     *desc = BUILD_DESCR (LOCUNUSED, PAGED_OUT, PT_PAGE);
  405.     (*PFlushP) (tmp-PAGESIZE);
  406.     }
  407.   Permit ();
  408.   }
  409.  
  410. /* Second pass */
  411.  
  412. /* Because cur might be removed at the end of the loop,
  413.  * its successor is stored at the start of each looping
  414.  */
  415.  
  416. end_page -= PAGESIZE;
  417. for (cur = (struct FrameDescr*)FrameList.lh_Head,
  418.      succ = (struct FrameDescr*)cur->FDNode.mln_Succ;
  419.      cur->FDNode.mln_Succ != NULL;
  420.      cur = succ, succ = (struct FrameDescr*)cur->FDNode.mln_Succ)
  421.   {
  422.   if ((cur->PageType == PT_PAGE) &&
  423.       (cur->LogAddr >= start_page) && (cur->LogAddr <= end_page))
  424.     {
  425.     Forbid ();
  426.     *(cur->PageDescr) &= ~(USED | MODIFIED);
  427.     (*PFlushP) (cur->LogAddr);
  428.     Permit ();
  429.     cur->Modified = FALSE;
  430.     if (cur->PageNumOnDisk != LOCUNUSED)
  431.       {
  432.       FreePageOnDisk (cur->PageNumOnDisk);
  433.       cur->PageNumOnDisk = LOCUNUSED;
  434.       }
  435.     Remove ((struct Node*)cur);
  436.     AddHead (&FrameList, (struct Node*)cur);
  437.     }
  438.   }
  439. }
  440.  
  441. /***********************************************************************/
  442.  
  443. PRIVATE void NewConfigReceived (void)
  444.  
  445. {
  446. PRINT_DEB ("New config received", 0L);
  447.  
  448. if (NumPageFrames * PAGESIZE < CurrentConfig.MinMem)
  449.   {
  450.   /* There's memory missing */
  451.   int total_frames;
  452.  
  453.   PRINT_DEB ("Adding mem until %ld bytes", CurrentConfig.MinMem);
  454.   total_frames = CurrentConfig.MinMem / PAGESIZE;
  455.   while ((NumPageFrames < total_frames) && AddFrame (0L));
  456.   }
  457. else if (NumPageFrames * PAGESIZE > CurrentConfig.MaxMem)
  458.   {
  459.   struct TrapStruct *DummyTrap;
  460.  
  461.   PRINT_DEB ("Removing mem until %ld bytes", CurrentConfig.MaxMem);
  462.   /* Fool the pagehandler by simulating a low memory condition.
  463.    * InformTask has to handle this as a special case.
  464.    */
  465.   Forbid ();
  466.   DummyTrap = (struct TrapStruct*)RemHead (&Free);
  467.   Permit ();
  468.   if (DummyTrap == NULL)
  469.     return;
  470.   DummyTrap->FaultAddress = NULL;     /* Marker for remove */
  471.   DummyTrap->RemFrameFlags = MEMF_ANY;
  472.   DummyTrap->FaultTask = (struct Task*)REDUCE_TASK;
  473.   AddPageReq (DummyTrap);
  474.   LowMem++;
  475.   SetSignal (1L << PageFaultSignal, 1L << PageFaultSignal);
  476.   }
  477. }
  478.  
  479. /***********************************************************************/
  480.  
  481. PRIVATE void HandleVMMsg (void)
  482.  
  483. {
  484. struct VMMsg *VMMsg;
  485.  
  486. while ((VMMsg = (struct VMMsg*)GetMsg (PageHandlerPort)) != NULL)
  487.   {
  488.   switch (VMMsg->VMCommand)
  489.     {
  490.     case VMCMD_LockPage: 
  491.                LockPage (VMMsg->PageAddress);
  492.                break;
  493.  
  494.     case VMCMD_UnlockAllPages:
  495.                UnlockAllPages ();
  496.                break;
  497.  
  498.     case VMCMD_FreePages:
  499. /*             PRINT_DEB ("FreeRequest from task", 0L);
  500.                PRINT_DEB (VMMsg->VMSender->tc_Node.ln_Name, 0L);
  501. */
  502.                FreePages (VMMsg->FreeAddress, VMMsg->FreeSize);
  503.                break;
  504.  
  505.     case VMCMD_NewConfig:
  506.                NewConfigReceived ();
  507.                break;
  508.  
  509.     case VMCMD_NewWriteBuffer:
  510.                PRINT_DEB ("Received new write buffer. Size: %ld", VMMsg->NewWriteBufferSize);
  511.                NewCache (VMMsg->NewWriteBuffer, VMMsg->NewWriteBufferSize);
  512.                break;
  513.  
  514.     default: PRINT_DEB ("Received unknown msg type", (ULONG)VMMsg->VMCommand);
  515.     }
  516.   if (VMMsg->ReplySignal != NULL)
  517.     Signal (VMMsg->VMSender, 1L << VMMsg->ReplySignal);
  518.   else
  519.     FreeMem (VMMsg, sizeof (struct VMMsg));
  520.   }
  521. }
  522.  
  523. /***********************************************************************/
  524.  
  525. void PageHandler (void)
  526.  
  527. {
  528. ULONG ReceivedSignals;
  529. ULONG WaitMask;
  530. struct VMMsg *InitMsg;
  531. int rc;
  532. BOOL quit = FALSE;
  533.  
  534. if ((rc = InitPageHandler ()) != SUCCESS)
  535.   {
  536.   PRINT_DEB ("Init failed", 0L);
  537.   InitError (rc);
  538.   Cleanup_PageHandler ();
  539.   Signal ((struct Task*)VM_ManagerProcess, 1L << InitPort->mp_SigBit);
  540.   return;
  541.   }
  542.  
  543. /* Tell VM_Manager that the page handler has been initialized correctly */
  544. if ((InitMsg = DoOrigAllocMem (sizeof (struct VMMsg), MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
  545.   {
  546.   PRINT_DEB ("Not enough memory for init msg", 0L);
  547.   Cleanup_PageHandler ();
  548.   Signal ((struct Task*)VM_ManagerProcess, 1L << InitPort->mp_SigBit);
  549.   return;
  550.   }
  551.  
  552. InitMsg->VMSender = FindTask (NULL);
  553. InitMsg->VMCommand = VMCMD_InitReady;
  554. InitMsg->ReplySignal = NULL;          /* VM_Manager should free this */
  555. PutMsg (InitPort, (struct Message*)InitMsg);
  556.  
  557. WaitMask = (1L << PageFaultSignal) |
  558.            (1L << PageHandlerQuitSignal) |
  559.            (1L << ReplySignal) |
  560.            (1L << PageHandlerPort->mp_SigBit) |
  561.            (1L << ResetSignal);
  562.  
  563. while (!quit)
  564.   {
  565.   /* PRINT_DEB ("Waiting for signals", 0L); */
  566.   ReceivedSignals = Wait (WaitMask);
  567.   /* PRINT_DEB ("Received signals %lx", ReceivedSignals); */
  568.  
  569.   if (ReceivedSignals & (1L << PageFaultSignal))
  570.     {
  571.     /* PRINT_DEB ("Received page fault signal", 0L); */
  572.     HandlePageFault ();
  573.     }
  574.  
  575.   if (ReceivedSignals & (1L << ReplySignal))
  576.     {
  577.     /* handle return from paging device.
  578.      * Page has been either written out or read in.
  579.      */
  580.     /* PRINT_DEB ("Received return signal", 0L); */
  581.     HandleReturn ();
  582.     CheckWaitingFaults ();
  583.     }
  584.  
  585.   if (ReceivedSignals & (1L << PageHandlerPort->mp_SigBit))
  586.     {
  587.     /* PRINT_DEB ("VMMsg received", 0L); */
  588.     HandleVMMsg ();
  589.     }
  590.  
  591.   if (ReceivedSignals & (1L << PageHandlerQuitSignal))
  592.     {
  593.     PRINT_DEB ("Received quit signal", 0L);
  594.     quit = TRUE;
  595.     }
  596.  
  597.   if (ReceivedSignals & (1L << ResetSignal))
  598.     {
  599.     PRINT_DEB ("Received ResetSignal", 0L);
  600.     PRINT_DEB ("PagefaultsInProgress = %ld", (LONG)PageFaultsInProgress);
  601.     ResetInProgress = TRUE;
  602.     }
  603.  
  604.   if (ResetInProgress && PageFaultsInProgress == 0)
  605.     {
  606.     if (CurrentConfig.PageDev == PD_FILE)
  607.       {
  608.       PRINT_DEB ("Waiting 2 seconds", 0L);
  609.       Delay (100L);  /* Wait 2 seconds for the fs to calm down */
  610.       }
  611.     PRINT_DEB ("No pagefaults in progress. Ready for reset", 0L);
  612.     PRINT_DEB ("Allowing reset", 0L);
  613.     ResetHandlerDone (ResetHandlerData);
  614.     }
  615.   }
  616.  
  617. Cleanup_PageHandler ();
  618. PRINT_DEB ("Exiting", 0L);
  619. }
  620.